package Entity;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 习题自动批改核心实现类（修复空指针问题）
 * 功能：读取习题文件（含正确答案）和练习文件（含用户答案），自动对比批改，生成带评价的批改文件
 */
public class ExerciseCorrector {
    // 配置项（可根据需求调整）
    private static final double SINGLE_QUESTION_SCORE = 2.0; // 单题分值（2分制）
    private static final String CORRECTION_SUFFIX = "_批改结果"; // 批改文件后缀
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final String[] CORRECTION_HEADERS = {
            "序号", "习题ID", "题目", "正确答案", "用户答案",
            "批改结果", "得分", "题型", "批改时间"
    };

    /**
     * 核心批改方法：入口函数
     * @param exerciseFilePath 习题文件路径（CSV格式，需包含正确答案）
     * @param practiceFilePath 练习文件路径（CSV格式，需包含用户答案）
     * @return 批改文件保存路径
     * @throws IOException 文件读写异常
     */
    public String correctAndSave(String exerciseFilePath, String practiceFilePath) throws IOException {
        // 1. 验证文件存在性
        validateFileExists(exerciseFilePath, "习题文件");
        validateFileExists(practiceFilePath, "练习文件");

        // 2. 读取习题和练习数据（依赖CsvFileUtil工具类）
        List<Exercise> exerciseList = CsvFileUtil.readExercises(exerciseFilePath);
        List<PracticeRecord> practiceList = CsvFileUtil.readPracticeRecords(practiceFilePath);

        // 3. 数据一致性校验
        validateDataConsistency(exerciseList, practiceList);

        // 4. 构建习题ID映射（提高匹配效率）
        Map<String, Exercise> exerciseMap = buildExerciseIdMap(exerciseList);

        // 5. 逐题批改，生成批改数据
        CorrectionResult result = calculateCorrectionResult(exerciseMap, practiceList);

        // 6. 生成批改文件内容（含详细记录和统计评价）
        List<String[]> correctionData = buildCorrectionData(result);

        // 7. 写入批改文件并返回路径
        String correctionFilePath = generateCorrectionFilePath(practiceFilePath);
        writeCorrectionToCsv(correctionData, correctionFilePath);

        // 打印批改总结（控制台可视化）
        printCorrectionSummary(result, correctionFilePath);

        return correctionFilePath;
    }

    /**
     * 验证文件是否存在
     */
    private void validateFileExists(String filePath, String fileType) {
        File file = new File(filePath);
        if (!file.exists() || !file.isFile()) {
            throw new IllegalArgumentException(fileType + "不存在或不是文件：" + filePath);
        }
    }

    /**
     * 校验习题和练习数据一致性（数量、习题ID匹配）
     */
    private void validateDataConsistency(List<Exercise> exercises, List<PracticeRecord> practices) {
        // 校验数量一致
        if (exercises.size() != practices.size()) {
            throw new RuntimeException(
                    String.format("数据不一致：习题数[%d] != 练习记录数[%d]", exercises.size(), practices.size())
            );
        }

        // 校验习题ID完全匹配
        Set<String> exerciseIds = new HashSet<>();
        for (Exercise exercise : exercises) {
            exerciseIds.add(exercise.getExerciseId());
        }
        for (PracticeRecord practice : practices) {
            if (!exerciseIds.contains(practice.getExerciseId())) {
                throw new RuntimeException("练习记录包含无效习题ID：" + practice.getExerciseId());
            }
        }
    }

    /**
     * 构建习题ID到习题对象的映射
     */
    private Map<String, Exercise> buildExerciseIdMap(List<Exercise> exercises) {
        Map<String, Exercise> exerciseMap = new HashMap<>(exercises.size());
        for (Exercise exercise : exercises) {
            exerciseMap.put(exercise.getExerciseId(), exercise);
        }
        return exerciseMap;
    }

    /**
     * 逐题计算批改结果（核心逻辑，修复空指针问题）
     */
    private CorrectionResult calculateCorrectionResult(
            Map<String, Exercise> exerciseMap, List<PracticeRecord> practiceList) {
        CorrectionResult result = new CorrectionResult();
        String correctionTime = DATE_FORMAT.format(new Date());

        for (int i = 0; i < practiceList.size(); i++) {
            PracticeRecord practice = practiceList.get(i);
            Exercise exercise = exerciseMap.get(practice.getExerciseId());

            // 构建题目信息
            String question = String.format("%d %c %d = ?",
                    exercise.getNum1(), exercise.getOperator(), exercise.getNum2());
            String questionType = (exercise.getOperator() == '+') ? "加法" : "减法";

            // 处理用户答案（未答题/空答案）- 安全处理
            Integer userAnswer = practice.getUserAnswer();
            String userAnswerStr = (userAnswer == null) ? "未答题" : userAnswer.toString();

            // 处理正确答案（防止null，习题生成时应保证正确答案非空，但增加防护）
            Integer correctAnswer = exercise.getCorrectAnswer();
            String correctAnswerStr = (correctAnswer == null) ? "无正确答案" : correctAnswer.toString();

            // 批改判断（未答题/正确答案为空 均视为错误）
            boolean isCorrect = (userAnswer != null) && (correctAnswer != null) && userAnswer.equals(correctAnswer);
            double score = isCorrect ? SINGLE_QUESTION_SCORE : 0.0;

            // 构建单题批改记录
            SingleCorrectionRecord singleRecord = new SingleCorrectionRecord(
                    i + 1,
                    exercise.getExerciseId(),
                    question,
                    correctAnswerStr, // 使用安全处理后的正确答案字符串
                    userAnswerStr,
                    isCorrect ? "正确" : "错误",
                    score,
                    questionType,
                    correctionTime
            );

            // 更新统计数据
            result.addSingleRecord(singleRecord);
            if (isCorrect) {
                result.incrementCorrectCount();
                result.updateTypeCorrectCount(questionType);
            }
            result.updateTypeTotalCount(questionType);
        }

        // 计算总分和正确率
        result.calculateTotalScore(SINGLE_QUESTION_SCORE);
        result.calculateAccuracy();
        return result;
    }

    /**
     * 构建完整的批改文件数据（含表头、答题记录、统计评价）
     */
    private List<String[]> buildCorrectionData(CorrectionResult result) {
        List<String[]> correctionData = new ArrayList<>();

        // 1. 添加表头
        correctionData.add(CORRECTION_HEADERS);

        // 2. 添加逐题批改记录
        for (SingleCorrectionRecord singleRecord : result.getSingleRecords()) {
            correctionData.add(new String[]{
                    String.valueOf(singleRecord.getSerialNumber()),
                    singleRecord.getExerciseId(),
                    singleRecord.getQuestion(),
                    singleRecord.getCorrectAnswer(),
                    singleRecord.getUserAnswer(),
                    singleRecord.getCorrectionResult(),
                    String.format("%.1f", singleRecord.getScore()), // 分值保留1位小数
                    singleRecord.getQuestionType(),
                    singleRecord.getCorrectionTime()
            });
        }

        // 3. 添加统计评价信息（空行分隔）
        correctionData.add(new String[]{});
        correctionData.add(new String[]{"===== 批改统计评价 =====", "", "", "", "", "", "", "", ""});
        correctionData.add(new String[]{"总题数", String.valueOf(result.getTotalCount()), "", "", "", "", "", "", ""});
        correctionData.add(new String[]{"做对题数", String.valueOf(result.getCorrectCount()), "", "", "", "", "", "", ""});
        correctionData.add(new String[]{"做错题数", String.valueOf(result.getTotalCount() - result.getCorrectCount()), "", "", "", "", "", "", ""});
        correctionData.add(new String[]{"总分", String.format("%.1f", result.getTotalScore()), "", "", "", "", "", "", ""});
        correctionData.add(new String[]{"总正确率", String.format("%.2f%%", result.getAccuracy()), "", "", "", "", "", "", ""});

        // 4. 添加题型细分统计
        correctionData.add(new String[]{"", "", "", "", "", "", "", "", ""});
        correctionData.add(new String[]{"===== 题型细分统计 =====", "", "", "", "", "", "", "", ""});
        Map<String, Integer> typeTotalMap = result.getTypeTotalCountMap();
        Map<String, Integer> typeCorrectMap = result.getTypeCorrectCountMap();

        for (String questionType : typeTotalMap.keySet()) {
            int total = typeTotalMap.get(questionType);
            int correct = typeCorrectMap.getOrDefault(questionType, 0);
            double typeAccuracy = total == 0 ? 0.0 : (double) correct / total * 100;

            // 修复：之前的数组长度错误，每个题型统计占3行，每行1列有效数据
            correctionData.add(new String[]{questionType + "总题数：" + total});
            correctionData.add(new String[]{questionType + "做对题数：" + correct});
            correctionData.add(new String[]{questionType + "正确率：" + String.format("%.2f%%", typeAccuracy)});
            correctionData.add(new String[]{}); // 空行分隔
        }

        // 5. 添加评价建议
        correctionData.add(new String[]{});
        correctionData.add(new String[]{"===== 学习建议 =====", "", "", "", "", "", "", "", ""});
        correctionData.add(new String[]{generateSuggestion(result)});

        return correctionData;
    }

    /**
     * 生成个性化学习建议
     */
    private String generateSuggestion(CorrectionResult result) {
        double totalAccuracy = result.getAccuracy();
        StringBuilder suggestion = new StringBuilder();

        if (totalAccuracy >= 90) {
            suggestion.append("优秀！你对习题的掌握程度很好，继续保持！");
        } else if (totalAccuracy >= 70) {
            suggestion.append("良好！大部分题目都能做对，建议重点复习做错的题型，巩固薄弱环节。");
        } else if (totalAccuracy >= 50) {
            suggestion.append("一般！基础知识点需要加强，建议多做同类习题，重点练习错题对应的题型。");
        } else {
            suggestion.append("需努力！建议重新学习相关知识点，先掌握基础题型，再逐步提升难度。");
        }

        // 针对具体题型的建议
        Map<String, Integer> typeTotalMap = result.getTypeTotalCountMap();
        Map<String, Integer> typeCorrectMap = result.getTypeCorrectCountMap();
        for (String questionType : typeTotalMap.keySet()) {
            int total = typeTotalMap.get(questionType);
            int correct = typeCorrectMap.getOrDefault(questionType, 0);
            double typeAccuracy = total == 0 ? 0.0 : (double) correct / total * 100;

            if (typeAccuracy < 60) {
                suggestion.append(String.format(" 你的%s题型正确率较低（%.2f%%），需重点强化练习。", questionType, typeAccuracy));
            }
        }

        return suggestion.toString();
    }

    /**
     * 生成批改文件路径（在练习文件同目录下，添加后缀）
     */
    private String generateCorrectionFilePath(String practiceFilePath) {
        int lastDotIndex = practiceFilePath.lastIndexOf(".");
        if (lastDotIndex == -1) {
            return practiceFilePath + CORRECTION_SUFFIX + ".csv";
        }
        return practiceFilePath.substring(0, lastDotIndex) + CORRECTION_SUFFIX + ".csv";
    }

    /**
     * 将批改结果写入CSV文件（确保文件流正确关闭）
     */
    private void writeCorrectionToCsv(List<String[]> correctionData, String filePath) throws IOException {
        try (com.csvreader.CsvWriter csvWriter = new com.csvreader.CsvWriter(
                filePath, ',', StandardCharsets.UTF_8)) {
            for (String[] row : correctionData) {
                csvWriter.writeRecord(row);
            }
        }
        System.out.println("批改文件写入成功！");
    }

    /**
     * 打印批改总结（控制台输出，方便用户快速查看）
     */
    private void printCorrectionSummary(CorrectionResult result, String correctionFilePath) {
        System.out.println("\n" + "=".repeat(50));
        System.out.println("          习题批改完成！");
        System.out.println("=".repeat(50));
        System.out.println("总题数：" + result.getTotalCount() + " 道");
        System.out.println("做对：" + result.getCorrectCount() + " 道 | 做错：" + (result.getTotalCount() - result.getCorrectCount()) + " 道");
        System.out.println("总分：" + String.format("%.1f", result.getTotalScore()) + " 分（满分：" + String.format("%.1f", result.getTotalCount() * SINGLE_QUESTION_SCORE) + " 分）");
        System.out.println("总正确率：" + String.format("%.2f%%", result.getAccuracy()));

        // 打印题型细分统计
        Map<String, Integer> typeTotalMap = result.getTypeTotalCountMap();
        Map<String, Integer> typeCorrectMap = result.getTypeCorrectCountMap();
        System.out.println("\n【题型细分统计】");
        for (String questionType : typeTotalMap.keySet()) {
            int total = typeTotalMap.get(questionType);
            int correct = typeCorrectMap.getOrDefault(questionType, 0);
            double typeAccuracy = total == 0 ? 0.0 : (double) correct / total * 100;
            System.out.printf("%s：%d题 / 做对%d题 / 正确率%.2f%%%n",
                    questionType, total, correct, typeAccuracy);
        }

        System.out.println("\n【学习建议】");
        System.out.println(generateSuggestion(result));
        System.out.println("\n批改文件保存路径：" + correctionFilePath);
        System.out.println("=".repeat(50) + "\n");
    }

    /**
     * 内部静态类：封装单题批改记录
     */
    private static class SingleCorrectionRecord {
        private final int serialNumber; // 序号
        private final String exerciseId; // 习题ID
        private final String question; // 题目
        private final String correctAnswer; // 正确答案（字符串形式，避免空指针）
        private final String userAnswer; // 用户答案
        private final String correctionResult; // 批改结果（正确/错误）
        private final double score; // 得分
        private final String questionType; // 题型（加法/减法）
        private final String correctionTime; // 批改时间

        public SingleCorrectionRecord(int serialNumber, String exerciseId, String question,
                                      String correctAnswer, String userAnswer, String correctionResult,
                                      double score, String questionType, String correctionTime) {
            this.serialNumber = serialNumber;
            this.exerciseId = exerciseId;
            this.question = question;
            this.correctAnswer = correctAnswer; // 直接接收处理后的字符串
            this.userAnswer = userAnswer;
            this.correctionResult = correctionResult;
            this.score = score;
            this.questionType = questionType;
            this.correctionTime = correctionTime;
        }

        // Getter方法
        public int getSerialNumber() { return serialNumber; }
        public String getExerciseId() { return exerciseId; }
        public String getQuestion() { return question; }
        public String getCorrectAnswer() { return correctAnswer; }
        public String getUserAnswer() { return userAnswer; }
        public String getCorrectionResult() { return correctionResult; }
        public double getScore() { return score; }
        public String getQuestionType() { return questionType; }
        public String getCorrectionTime() { return correctionTime; }
    }

    /**
     * 内部静态类：封装整体批改结果（含统计数据）
     */
    private static class CorrectionResult {
        private final List<SingleCorrectionRecord> singleRecords = new ArrayList<>();
        private int totalCount; // 总题数
        private int correctCount; // 做对题数
        private double totalScore; // 总分
        private double accuracy; // 总正确率
        private final Map<String, Integer> typeTotalCountMap = new HashMap<>(); // 各题型总题数
        private final Map<String, Integer> typeCorrectCountMap = new HashMap<>(); // 各题型做对题数

        public CorrectionResult() {
            this.totalCount = 0;
            this.correctCount = 0;
            this.totalScore = 0.0;
            this.accuracy = 0.0;
        }

        // 添加单题记录（自动更新总题数）
        public void addSingleRecord(SingleCorrectionRecord record) {
            singleRecords.add(record);
            this.totalCount = singleRecords.size();
        }

        // 递增做对题数
        public void incrementCorrectCount() {
            this.correctCount++;
        }

        // 更新题型总题数
        public void updateTypeTotalCount(String questionType) {
            typeTotalCountMap.put(questionType, typeTotalCountMap.getOrDefault(questionType, 0) + 1);
        }

        // 更新题型做对题数
        public void updateTypeCorrectCount(String questionType) {
            typeCorrectCountMap.put(questionType, typeCorrectCountMap.getOrDefault(questionType, 0) + 1);
        }

        // 计算总分
        public void calculateTotalScore(double singleScore) {
            this.totalScore = this.correctCount * singleScore;
        }

        // 计算总正确率
        public void calculateAccuracy() {
            this.accuracy = (totalCount == 0) ? 0.0 : (double) correctCount / totalCount * 100;
        }

        // Getter方法
        public List<SingleCorrectionRecord> getSingleRecords() { return singleRecords; }
        public int getTotalCount() { return totalCount; }
        public int getCorrectCount() { return correctCount; }
        public double getTotalScore() { return totalScore; }
        public double getAccuracy() { return accuracy; }
        public Map<String, Integer> getTypeTotalCountMap() { return typeTotalCountMap; }
        public Map<String, Integer> getTypeCorrectCountMap() { return typeCorrectCountMap; }
    }

    // ------------------------------
    // 测试入口（可选：直接运行该类测试功能）
    // ------------------------------
    public static void main(String[] args) {
        try {
            // 示例：替换为实际的习题文件和练习文件路径
            String exerciseFile = "D:\\作业\\软件构造\\Exercise_Add_20231001_001.csv";
            String practiceFile = "D:\\作业\\软件构造\\Exercise_Add_20231001_001_Xiaoming_20251111.csv";

            // 执行批改
            ExerciseCorrector corrector = new ExerciseCorrector();
            String correctionFile = corrector.correctAndSave(exerciseFile, practiceFile);

            System.out.println("批改完成！文件路径：" + correctionFile);
        } catch (Exception e) {
            System.err.println("批改失败：" + e.getMessage());
            e.printStackTrace();
        }
    }
}